#include <assert.h>
#include <vector>
#include <string>
#include <map>

#include "dbapi.h"
#include "dbapi_provider.h"

class  CDbRecordSetImpl : public CDbRecordSet {
public:
	CDbRecordSetImpl(int nFieldCount, int nMax) {
		m_nFieldCount = nFieldCount;
		m_nMaxRecord = nMax;
		m_nRecordCount = 0;
		m_FieldNames.resize(nFieldCount);
	}
	virtual ~CDbRecordSetImpl() {
		m_FieldNames.clear();
		m_FieldValues.clear();
	}

	virtual void Release() {
		delete this;
	}

	virtual int FieldCount() { return m_nFieldCount; }
	virtual int RecordCount() { return m_nRecordCount; }

	virtual const char* FieldName(int nField) {
		if(nField<0 || nField>=m_nFieldCount) return NULL;
		return m_FieldNames[nField].c_str();
	}
	virtual const char* FieldValue(int nRow, int nField) {
		if(nField<0 || nField>=m_nFieldCount) return NULL;
		if(nRow<0 || nRow>=m_nRecordCount) return NULL;
		std::map<int, std::string>::iterator i;
		i = m_FieldValues.find(nRow*m_nFieldCount+nField);
		if(i==m_FieldValues.end()) return NULL;
		return i->second.c_str();
	}

	virtual void SetFieldName(int nField, const char* pName) {
		if(nField<0 || nField>=m_nFieldCount) {
			assert(0);
			return;
		}
		m_FieldNames[nField] = pName;
	}
	virtual void SetFieldValue(int nRow, int nField, const char* pValue) {
		if(nField<0 || nField>=m_nFieldCount) return;
		if(nRow<0 || nRow>=m_nMaxRecord) return;
		if(nRow>=m_nRecordCount) m_nRecordCount = nRow + 1;
		m_FieldValues[nRow*m_nFieldCount+nField] = pValue;
	}

private:
	int m_nFieldCount, m_nRecordCount, m_nMaxRecord;
	std::vector<std::string> m_FieldNames;
	std::map<int, std::string> m_FieldValues;
};

CDbRecordSet* CDbRecordSet::New(int nFieldCount, int nMax)
{
	return new CDbRecordSetImpl(nFieldCount, nMax);
}

CDbClient::CDbClient()
{
	m_nErrorCode = 0;
	m_szErrorMsg[0] = '\0';
}

CDbClient::~CDbClient()
{
}

void CDbClient::SetError(int nCode, const char* pMsg)
{
	m_nErrorCode = nCode;
	strcpy(m_szErrorMsg, pMsg);
}

static CDbProvider* g_Providers[10];
static unsigned int g_ProviderCount = 0;
extern void* _dbprovider_sqlite;

void IDbClient::GlobalInit()
{
	_dbprovider_sqlite = _dbprovider_sqlite;
	for(unsigned int i=0; i<g_ProviderCount; i++) {
		g_Providers[i]->Init();
	}
}

void IDbClient::GlobalFinal()
{
	for(unsigned int i=0; i<g_ProviderCount; i++) {
		g_Providers[i]->Final();
	}
}

IDbClient* IDbClient::New(const char* pConnStr)
{
	std::map<std::string, std::string> Map;
	if(!CrackConnString(pConnStr, Map))
		return NULL;

	std::map<std::string, std::string>::iterator i;
	i = Map.find("provider");
	if(i==Map.end()) return NULL;

	CDbProvider* pProvider = CDbProvider::GetProvider(i->second.c_str());
	if(!pProvider) return NULL;

	return pProvider->CreateClient(pConnStr);
}

CDbProvider::CDbProvider()
{
	g_Providers[g_ProviderCount++] = this;
}

CDbProvider::~CDbProvider()
{
}

CDbProvider* CDbProvider::GetProvider(const char* pName)
{
	for(unsigned int i=0; i<g_ProviderCount; i++) {
		if(strcmp(g_Providers[i]->GetName(), pName)==0) return g_Providers[i];
	}
	return NULL;
}

unsigned int CDbProvider::GetProviderCount()
{
	return g_ProviderCount;
}

CDbProvider* CDbProvider::GetProvider(unsigned int nIndex)
{
	if(nIndex>=g_ProviderCount) return NULL;
	return g_Providers[nIndex];
}

bool CrackConnString(const char* pConnStr, std::map<std::string, std::string>& Map)
{
	int i=0;
	char str[1024];
	char *head, *tail;
	char *key, *value;

	if(strlen(pConnStr) >= sizeof(str))
		return false;

	strcpy(str, pConnStr);
	Map.clear();

	head = tail = str;
	for (i=0; i<10000; ++i) {
		// get name
		tail = strchr(head, '=');
		if(tail==NULL) return false;
		*tail = '\0';
		key = head;
		// get value
		value = tail+1;
		tail = strchr(value, ';');
		if(tail==NULL) {
			head = head + strlen(head);
		} else {
			*tail = '\0';
			head = tail+1;
		}

		Map[key] = value;

		if(*head=='\0') break;
	}

	return true;
}
